import { watch } from 'vue';
import { LOWCODE_COMPONENT_DATA } from '../constants/constant';
import { isPrimitive, isString, isDef } from './is';

export const lowCodeAttr = ['type', 'body', 'api', 'initApi', 'actions', 'dialog']; // 低代码的属性，不赋值到组件上

export function commonFilterAttr(schema, excludes) {
  const attr = {};
  for (const key in schema) {
    const value = schema[key];
    if (!excludes.includes(key)) {
      attr[key] = value;
    }
  }
  return attr;
}

/**
 *
 * @param {*} schema
 * @param {*} reflectAttr 要替换属性名的对象
 */
export function filterAttr(schema, reflectAttr) {
  const attr = {};
  for (const key in schema) {
    if (!lowCodeAttr.includes(key)) {
      const value = schema[key];
      if (reflectAttr) {
        if (reflectAttr[key]) {
          attr[reflectAttr[key]] = value;
        } else {
          attr[key] = value;
        }
      } else {
        attr[key] = value;
      }
    }
  }
  return attr;
}

/**
 *
 * @param {*} excludeAttrs 不包括的属性
 * @param {*} schema
 * @param {*} reflectAttr 要替换属性名的对象
 */
export function filterAttrByExclude(excludeAttrs, schema, reflectAttr) {
  const attr = {};
  for (const key in schema) {
    if (!lowCodeAttr.includes(key)) {
      const value = schema[key];
      if (!excludeAttrs.includes(key)) {
        if (reflectAttr) {
          if (reflectAttr[key]) {
            attr[reflectAttr[key]] = value;
          } else {
            attr[key] = value;
          }
        } else {
          attr[key] = value;
        }
      }
    }
  }
  return attr;
}

/**
 *
 * @param {*} inCludeAttrs 包括的属性
 * @param {*} schema
 * @param {*} reflectAttr 要替换属性名的对象
 */
export function filterAttrByInclude(inCludeAttrs, schema, reflectAttr) {
  const attr = {};
  for (const key in schema) {
    if (!lowCodeAttr.includes(key)) {
      const value = schema[key];
      if (inCludeAttrs.includes(key)) {
        if (reflectAttr) {
          if (reflectAttr[key]) {
            attr[reflectAttr[key]] = value;
          } else {
            attr[key] = value;
          }
        } else {
          attr[key] = value;
        }
      }
    }
  }
  return attr;
}

export function plainFilterAttr(obj, arr) {
  const attr = {};
  for (const key in obj) {
    if (!arr.includes(key)) {
      const value = obj[key];
      attr[key] = value;
    }
  }
  return attr;
}

export function handleObject(paramsDatas, instance) {
  if (!paramsDatas) {
    return {};
  }
  for (const key in paramsDatas) {
    const value = paramsDatas[key];
    const rs = replaceValue(value, instance);
    paramsDatas[key] = rs;
  }
  return paramsDatas;
}

const reg = /(\$\{[a-zA-Z0-9_]+\})/g;
export function replaceValue(str, instance) {
  if (!isString(str)) {
    return str;
  }
  const result = findVarName(str);
  if (result === false) {
    return str;
  }
  result.forEach((item) => {
    str = findLowCodeComponentDataAndReplace(str, item, instance);
  });
  return str;
}

export function findVarName(str) {
  if (!isString(str)) {
    return false;
  }
  const result = str.match(reg);
  if (!result || !result.length) {
    return false;
  }
  return result;
}

export function findLowCodeComponentDataAndReplace(str, placeholder, instance) {
  const rs = findVarByName(instance);
  if (rs === false) {
    return str;
  }
  const lowCodeComponentData = rs.data;
  const varName = placeholder.substring(2, placeholder.length - 1);
  if (Reflect.has(lowCodeComponentData, varName)) {
    const value = Reflect.get(lowCodeComponentData, varName);
    if (isPrimitive(value)) {
      return str.replaceAll(placeholder, value);
    } else {
      const rs = str.replaceAll(placeholder, JSON.stringify(value));
      try {
        return JSON.parse(rs);
      } catch (error) {
        console.error(error);
        return rs;
      }
    }
  }

  const preInstance = rs.instance;
  const parent = preInstance.parent;
  if (parent) {
    return findLowCodeComponentDataAndReplace(str, placeholder, parent);
  }
  return str;
}

export function findVarByName(instance, varName = LOWCODE_COMPONENT_DATA) {
  if (Reflect.has(instance.setupState, varName)) {
    return {
      data: Reflect.get(instance.setupState, varName),
      instance,
    };
  }
  const parent = instance.parent;
  if (parent) {
    return findVarByName(parent, varName);
  }
  return false;
}

/**
 *
 * @param {*} str
 * @param {*} instance
 * @param {*} refVar
 * @param {*} resolver 是否解析字符串的值
 * @returns
 */
export function watchText(str: string, instance, refVar) {
  const vars = findVarName(str);
  if (vars === false) {
    return;
  }
  vars.forEach((item) => {
    findVarAndWatch(str, item, instance, refVar);
  });
}

function findVarAndWatch(str, placeholder, instance, refVar) {
  const rs = findVarByName(instance);
  if (rs === false) {
    return;
  }
  const lowCodeComponentData = rs.data;
  const varName = placeholder.substring(2, placeholder.length - 1);
  if (Reflect.has(lowCodeComponentData, varName)) {
    watch(
      () => lowCodeComponentData[varName],
      () => {
        const value = lowCodeComponentData[varName];
        let _value: string | undefined = undefined;
        if (isDef(value)) {
          _value = JSON.stringify(value);
        }
        const _str = str.replaceAll(placeholder, _value);
        try {
          refVar.value = eval(_str);
        } catch (error) {
          console.error(error);
        }
      },
      {
        immediate: true,
      },
    );
    return;
  }
  const preInstance = rs.instance;
  const parent = preInstance.parent;
  if (parent) {
    findVarAndWatch(str, placeholder, parent, refVar);
  }
}

export function downFileByUrl(url, fileName) {
  const a = document.createElement('a');
  a.setAttribute('target', '__blank');
  a.href = url;
  a.download = fileName;
  a.click();
}
